
#include "StdAfx.h"
#include "LuaGlue.h"

#pragma comment( lib, "lua52.lib" )

LuaGlue::LuaGlue(){
	L_ = 0;
}

LuaGlue::~LuaGlue(){
	lua_close( L_ );
}

int LuaGlue::initialize( char* script ){
	if( L_ )
		lua_close( L_ );

	L_ = luaL_newstate();
	luaL_openlibs( L_ );

	if( luaL_dofile( L_, script ) != 0 ){
		std::cout << lua_tostring( L_, -1 ) << std::endl;
		return DEFAULT_FAIL;
	}
	
	return DEFAULT_SUCCESS;
}

void LuaGlue::stack_dump( char* name ){
	if( name )
		std::cout << name << std::endl;

	int i = 0;
	int t = 0;
	int top = lua_gettop( L_ );

	if(! top )
		std::cout << "stack empty" << std::endl;

	for( i = 1 ; i <= top ; i++ ){
		t = lua_type( L_, i );

		switch( t ){
		case LUA_TSTRING:
			{
				std::cout << lua_tostring( L_, i ) << std::endl;
			};
			break;

		case LUA_TBOOLEAN:
			{
				std::cout << lua_toboolean( L_, i ) << std::endl;
			};
			break;

		case LUA_TNUMBER:
			{
				std::cout << lua_tonumber( L_, i ) << std::endl;
			}
			break;

		default :
			{
				std::cout << lua_typename( L_, t ) << std::endl;
			}
			break;
		}
	}	
}

int LuaGlue::call_va( const char* func, const char* sig, ... ){
	va_list vl;
	int narg = 0;
	int nres = 0;
	int pop_count = 0;

	va_start( vl, sig );
	lua_getglobal( L_, func );

	for( narg = 0 ; *sig ; narg++ ){
		luaL_checkstack( L_, 1, "too many args" );

		switch( *sig++ ){
		case 'd' :
			{
				lua_pushnumber( L_, va_arg( vl, double ) );
			}
			break;

		case 'u' :
			{
				lua_pushnumber( L_, va_arg( vl, __int64 ) );
			}
			break;

		case 'i' :
			{
				lua_pushinteger( L_, va_arg( vl, int ) );
			}
			break;

		case 's' :
			{
				lua_pushstring( L_, va_arg( vl, char* ) );
			}
			break;

		case '>' : goto endargs;
			
		default:
			{
				return DEF_ERR_UNKOWN_TYPE;
			}
			break;
		}
	}

endargs:

	nres = strlen( sig );

	if( lua_pcall( L_, narg, nres, 0 ) != 0 ){
		std::cout << lua_tostring( L_, -1 ) << std::endl;
		return DEF_ERR_CALL;
	}

	pop_count = nres;
	nres = -nres;

	while( *sig ){
		switch( *sig++ ){
		case 'd' :
			{
				if(! lua_isnumber( L_, nres ) )
					return DEF_ERR_TYPE;
				
				*va_arg( vl, double* ) = lua_tonumber( L_, nres );
			}
			break;

		case 'i' :
			{
				if(! lua_isnumber( L_, nres ) )
					return DEF_ERR_TYPE;
				
				*va_arg( vl, int* ) = lua_tointeger( L_, nres );
			}
			break;

		case 'u' :
			{
				if(! lua_isnumber( L_, nres ) )
					return DEF_ERR_TYPE;
				
				*va_arg( vl, __int64* ) = lua_tonumber( L_, nres );
			}
			break;

		case 's' :
			{
				if(! lua_isstring( L_, nres ) )
					return DEF_ERR_TYPE;
				
				*va_arg( vl, const char** ) = lua_tostring( L_, nres );
			}
			break;

		default :
			{
				return DEF_ERR_UNKOWN_TYPE;
			}
		}

		nres++;
	}

	va_end( vl );

	lua_pop( L_, pop_count );

	return 0;
}

int LuaGlue::call_va( const char* func, int in_arg_count, const char* sig, ... ){
	va_list vl;
	int narg = 0;
	int nres = 0;
	int pop_count = 0;

	va_start( vl, sig );
	lua_getglobal( L_, func );

	if(! in_arg_count )
		in_arg_count = 1;

	luaL_checkstack( L_, in_arg_count, "too many args" );

	for( narg = 0 ; *sig ; narg++ ){
		switch( *sig++ ){
		case 'd' :
			{
				lua_pushnumber( L_, va_arg( vl, double ) );
			}
			break;

		case 'i' :
			{
				lua_pushinteger( L_, va_arg( vl, int ) );
			}
			break;

		case 's' :
			{
				lua_pushstring( L_, va_arg( vl, char* ) );
			}
			break;

		case '>' : goto endargs;
			
		default:
			{
				return DEF_ERR_UNKOWN_TYPE;
			}
			break;
		}
	}

endargs:

	nres = strlen( sig );

	if( lua_pcall( L_, narg, nres, 0 ) != 0 ){
		std::cout << lua_tostring( L_, -1 ) << std::endl;
		return DEF_ERR_CALL;
	}

	pop_count = nres;
	nres = -nres;

	while( *sig ){
		switch( *sig++ ){
		case 'd' :
			{
				if(! lua_isnumber( L_, nres ) )
					return DEF_ERR_TYPE;
				
				*va_arg( vl, double* ) = lua_tonumber( L_, nres );
			}
			break;

		case 'i' :
			{
				if(! lua_isnumber( L_, nres ) )
					return DEF_ERR_TYPE;
				
				*va_arg( vl, int* ) = lua_tointeger( L_, nres );
			}
			break;

		case 's' :
			{
				if(! lua_isstring( L_, nres ) )
					return DEF_ERR_TYPE;
				
				*va_arg( vl, const char** ) = lua_tostring( L_, nres );
			}
			break;

		default :
			{
				return DEF_ERR_UNKOWN_TYPE;
			}
		}

		nres++;
	}

	va_end( vl );

	lua_pop( L_, pop_count );

	return 0;
}
